package com.fcl.mylibrary.reflect;

import android.app.Activity;
import android.view.View;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Created by Administrator on 2017/3/4.
 */

public class ViewInjectUtils<T> {

    private static final String METHOD_SET_CONTENTVIEW = "setContentView";
    private static final String METHOD_FIND_VIEW_BY_ID = "findViewById";

    public static void inject(Activity activity) {
        injectContentView(activity);
        injectViews(activity);
        injectEvents(activity);
    }

    public static <T> void  inject(T t, View view) {
        injectViews(t,view);
    }

    /**
     * 注入布局文件
     * @param activity
     */
    private static void injectContentView(Activity activity) {
        Class<? extends Activity> clazz = activity.getClass();
        //查询类上是否存在ContentView注解
        ContentView contentView = clazz.getAnnotation(ContentView.class);
        if (contentView != null) {
            int contentViewLayoutId = contentView.value();
            try {
                Method method = clazz.getMethod(METHOD_SET_CONTENTVIEW, int.class);
                method.setAccessible(true);
                method.invoke(activity, contentViewLayoutId);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * activity注入view
     * @param activity
     */
    private static void injectViews(Activity activity) {
        Class<? extends Activity> clazz = activity.getClass();
        List<Field> allFields = getAllFields(clazz);
        //遍历成员变量
        for (Field field : allFields) {
            ViewInject viewInject = field.getAnnotation(ViewInject.class);
            if (viewInject != null) {
                int viewId  =viewInject.value();
                if (viewId != -1) {
                    try {
                        Method method = clazz.getMethod(METHOD_FIND_VIEW_BY_ID, int.class);
                        Object resView = method.invoke(activity, viewId);
                        field.setAccessible(true);
                        field.set(activity, resView);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    /**
     * 获取类以及所有父类的field
     * @param clazz
     * @return
     */
    private static List<Field> getAllFields(Class clazz) {
        List<Field> allFields = new ArrayList<>();
        Class curClazz = clazz;
        while (curClazz != null) {
            allFields.addAll(Arrays.asList(curClazz.getDeclaredFields()));
            curClazz = curClazz.getSuperclass();
        }
        return allFields;
    }

    /**
     * T注入view，T可以是fragment等控件
     * @param t
     * @param view
     * @param <T>
     */
    private static <T> void injectViews(T t, View view) {
        Class<? > clazz = t.getClass();
        List<Field> allFields = getAllFields(clazz);
        //遍历成员变量
        for (Field field : allFields) {
            ViewInject viewInject = field.getAnnotation(ViewInject.class);
            if (viewInject != null) {
                int viewId  =viewInject.value();
                if (viewId != -1) {
                    try {
                        Method method = view.getClass().getMethod(METHOD_FIND_VIEW_BY_ID, int.class);
                        Object resView = method.invoke(view, viewId);
                        field.setAccessible(true);
                        field.set(t, resView);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    private static void injectEvents(Activity activity) {
        Class<? extends Activity> clazz = activity.getClass();
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            Annotation annotation = method.getAnnotation(OnClick.class);
            if (annotation != null) {
                //获取OnClick注解上的EventBase注解
                Class<? extends Annotation> annotationType = annotation.annotationType();
                EventBase eventBase = annotationType.getAnnotation(EventBase.class);
                if (eventBase != null) {
                    //取出监听器名称、监听器类型以及调用的方法名
                    String listenerSetter = eventBase.listenerSetter();
                    Class<?> listenerType = eventBase.listenerType();
                    String methodName = eventBase.methodName();

                    //设置动态代理，OnClickListener的onClick方法实际上调用Activity中的对应方法
                    DynamicHandler handler = new DynamicHandler(activity);
                    handler.addMethod(methodName, method);
                    Object listener = Proxy.newProxyInstance(listenerType.getClassLoader(),
                            new Class[]{listenerType}, handler);

                    try {
                        int[] viewIds = ((OnClick)annotation).value();
                        //遍历所有view，设置事件
                        for (int viewId : viewIds) {
                            View view = activity.findViewById(viewId);
                            Method setListenerMethod = view.getClass()
                                    .getMethod(listenerSetter, listenerType);
                            setListenerMethod.invoke(view, listener);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

}
